home *** CD-ROM | disk | FTP | other *** search
/ Computer Select (Limited Edition) / Computer Select.iso / dobbs / v16n08 / pickles.lst < prev    next >
Encoding:
File List  |  1991-08-14  |  27.0 KB  |  904 lines

  1. _SCALIN╟ AN─ PRINTIN╟ FA╪E╪ FASTER_
  2. b∙ Greτ Pickles
  3.  
  4. [COMPLET┼ SOURCE]
  5.  
  6.  
  7. [LISTING ONE]
  8.  
  9. ;--------------------------------------------------------------------
  10. ;  Scale2To3  (c) Copyright 1991, Greg Pickles, All Rights Reserved
  11. ;
  12. ;  C callable assembly language routine to expand 2 lines of 200 DPI
  13. ;  bitmap to 3 lines of 300 DPI bitmap.  Assumes that all memory for
  14. ;  storing the lines is allocated outside this routine.
  15. ;--------------------------------------------------------------------
  16. .model    large,c
  17. .286
  18.     .data
  19.     ;-----------------------------------------------------------
  20.     ; The following table defines the output bit map to use for
  21.     ; each incoming 2x2 bit section.  The table is organized
  22.     ; as groups of 4 bytes even though only the first 3 in
  23.     ; each group is used.
  24.     ;-----------------------------------------------------------
  25. MapTbl    dw    0000000000000000b        ;0
  26.     dw    0000000000000000b
  27.     dw    0000000000000000b
  28.     dw    0
  29.  
  30.     dw    0000001100000000b        ;1
  31.     dw    0000001100000000b
  32.     dw    0000000000000000b
  33.     dw    0
  34.  
  35.     dw    0000011000000000b        ;2
  36.     dw    0000011000000000b
  37.     dw    0000000000000000b
  38.     dw    0
  39.  
  40.     dw    0000011100000000b        ;3
  41.     dw    0000011100000000b
  42.     dw    0000000000000000b
  43.     dw    0
  44.  
  45.     dw    0000000000000000b        ;4
  46.     dw    0000001100000000b
  47.     dw    0000001100000000b
  48.     dw    0
  49.  
  50.     dw    0000001100000000b        ;5
  51.     dw    0000001100000000b
  52.     dw    0000001100000000b
  53.     dw    0
  54.  
  55.     dw    0000011000000000b        ;6
  56.     dw    0000011100000000b
  57.     dw    0000001100000000b
  58.     dw    0
  59.  
  60.     dw    0000011100000000b        ;7
  61.     dw    0000011100000000b
  62.     dw    0000001100000000b
  63.     dw    0
  64.  
  65.     dw    0000000000000000b        ;8
  66.     dw    0000011000000000b
  67.     dw    0000011000000000b
  68.     dw    0
  69.  
  70.     dw    0000001100000000b        ;9
  71.     dw    0000011100000000b
  72.     dw    0000011000000000b
  73.     dw    0
  74.  
  75.     dw    0000011000000000b        ;a
  76.     dw    0000011000000000b
  77.     dw    0000011000000000b
  78.     dw    0
  79.  
  80.     dw    0000011100000000b        ;b
  81.     dw    0000011100000000b
  82.     dw    0000011000000000b
  83.     dw    0
  84.  
  85.     dw    0000000000000000b        ;c
  86.     dw    0000011100000000b
  87.     dw    0000011100000000b
  88.     dw    0
  89.  
  90.     dw    0000001100000000b        ;d
  91.     dw    0000011100000000b
  92.     dw    0000011100000000b
  93.     dw    0
  94.  
  95.     dw    0000011000000000b        ;e
  96.     dw    0000011100000000b
  97.     dw    0000011100000000b
  98.     dw    0
  99.  
  100.     dw    0000011100000000b        ;f
  101.     dw    0000011100000000b
  102.     dw    0000011100000000b
  103.     dw    0
  104.  
  105.     .code
  106. ;--------------------------------------------------------------------
  107. ; Scale2to3
  108. ;  Takes an array of bytes containing two lines of image
  109. ;  bit data and generates 3 lines of image bit data by
  110. ;  scaling the data in a 2:3 ratio in both directions.
  111. ;
  112. ; parameters
  113. ;  pointer to input array
  114. ;  pointer to output array (assumed to be already allocated)
  115. ;      >>>> This pointer must be word aligned!! <<<<
  116. ;  number of bytes per line of input data
  117. ;  invert flag - if non-zero (TRUE) incoming data will be inverted
  118. ;
  119. ; C prototype
  120. ;  void Scale2to3(char far*,char far*,short,short);
  121. ;
  122. ; returns
  123. ;  nothing
  124. ;--------------------------------------------------------------------
  125.     public    Scale2to3
  126. Scale2to3  proc uses si di ds,pIn:PTR,pOut:PTR,nBytes:WORD,InvFlg:Word
  127.  
  128. LOCAL    OuterCnt:WORD
  129.  
  130. S23_0:
  131.     mov    ax,nBytes    ;get number of bytes in input line
  132.     mov    OuterCnt,ax    ;set outer loop count
  133.  
  134.     mov    dx,ax        ;mult AX by 3/2 and put result in DX
  135.     shr    ax,1        ;div AX by 2
  136.     jnc    S23_10        ;if carry, then there is a fractional
  137.     inc    ax        ;  bytein the result, so inc for it
  138. S23_10:    add    dx,ax        ;save # of bytes in output line in dx
  139.  
  140.             ;fill the output buffer with 0
  141.     mov    cx,dx        ;multiply output line size by 3
  142.     shl    cx,1
  143.     add    cx,dx
  144.     mov    bx,cx        ;save CX to test for odd value later
  145.     shr    cx,1        ;divide CX by 2 to get word count
  146.     les    di,pOut        ;get pointer to output buffer
  147.     sub    ax,ax        ;get fill value
  148.     rep stosw
  149.     test    bl,1        ;see if extra byte to fill
  150.     jz    S23_15
  151.     stosb
  152.  
  153. S23_15:    mov    ax,@data
  154.     mov    ds,ax
  155.     mov    si,offset MapTbl
  156.     mov    cl,13        ;amount to shift initial output value
  157.  
  158.             ;top of loop that processes a byte of input
  159.             ; register usage:
  160.             ;  AX = input data and output data
  161.             ;  BX = ofset into map table
  162.             ;  CH = inner loop counter
  163.             ;  CL = shift count for this output group
  164.             ;  DX = size of output line
  165.             ;  DS:SI pointer to map table
  166.             ;  ES:DI pointer to output word
  167. S23_30:    les    di,pIn        ;get pointer to 1st input line
  168.     mov    ah,byte ptr es:[di]    ;get data from line 1
  169.     add    di,nBytes
  170.     mov    al,byte ptr es:[di]    ;get data from line 2
  171.  
  172.     test    InvFlg,0ffffh    ;see if we need to invert
  173.     jz    S23_35
  174.     not    ax
  175.  
  176. S23_35:    mov    ch,4         ;do 4 2-bit segments in next loop
  177.     mov    es,word ptr pOut+2    ;get segment address of output
  178.  
  179. S23_40:    rol    ax,2        ;bits we want are in 0,1,8,9
  180.     push    ax
  181.     and    ax,303h        ;mask out other bits
  182.     shl    ah,2        ;move bits from 8,9 to 10,11
  183.     or    al,ah        ;or them into al
  184.     sub    ah,ah        ;clear ah
  185.     shl    ax,3        ;ax now has offset into enlarge table
  186.     mov    bx,ax
  187.  
  188.     mov    ax,[si+bx]    ;get output value
  189.     rol    ax,cl        ;shift it
  190.     mov    di,word ptr pOut
  191.     or    es:[di],ax    ;or into output
  192.     
  193.     add    di,dx        ;get pointer to line 2 of output
  194.     mov    ax,[si+bx+2]    ;get output value
  195.     rol    ax,cl        ;shift it
  196.     or    es:[di],ax    ;or into output
  197.  
  198.     add    di,dx        ;get pointer to line 3 of output
  199.     mov    ax,[si+bx+4]    ;get output value
  200.     rol    ax,cl        ;shift it
  201.     or    es:[di],ax    ;or into output
  202.  
  203.     pop    ax
  204.             ;adjust the shift count for the output data
  205.             ;and the output pointer, if necessary
  206.     cmp    cl,1        ;see if we need to bump output pointer
  207.     ja    S23_60        ;jump if just need to adjust count
  208.                 ;CL is either 0 or 1 so it must become
  209.                 ; either 13 or 6, respectively
  210.                 ; NOTE: we are later going to sub 3
  211.                 ;       so set CL what we want + 3
  212.     mov    cl,9        ;assume CL was 1
  213.     je    S23_50        ;jump if CL=1
  214.     mov    cl,16        ;opps! guessed wrong so make it 13
  215.     inc    word ptr pOut    ;when CL goes from 0 to 13, need to
  216.                 ; bump the output pointer by 2
  217. S23_50:    inc    word ptr pOut    ;increment output pointer
  218. S23_60:    sub    cl,3
  219.  
  220.     dec    ch        ;decrement inner loop counter
  221.     jnz    S23_40        ;jump to inner loop if not 0
  222.  
  223.     inc    word ptr pIn    ;increment input pointer
  224.     dec    OuterCnt    ;decrement outer loop counter
  225.     jnz    S23_30
  226.  
  227.     ret
  228.  
  229. Scale2to3    endp
  230.     end
  231.  
  232.  
  233. [LISTING TWO]
  234.  
  235.  
  236. /*******************************************************************
  237.  * BUFIO.H  (c) Copyright 1991, Greg Pickles, All Rights Reserved
  238.  *
  239.  * Header file buffered file I/O.
  240.  *******************************************************************/
  241.  
  242.     /*---------------------------------------------------------------
  243.      * "standard" data types
  244.      *--------------------------------------------------------------*/
  245. typedef unsigned char   UCHAR;
  246. typedef unsigned short  USHORT;
  247. typedef short           SHORT;
  248. #define TRUE        1
  249. #define FALSE       0
  250.  
  251.  
  252. #define FILEBUFSIZE 8192
  253.  
  254.     /*---------------------------------------------------------------
  255.      * structure for buffered file I/O
  256.      *--------------------------------------------------------------*/
  257. typedef struct {
  258.     int     hFile;               // DOS file handle
  259.     SHORT   sMode;               // how file is opened
  260.     SHORT   sBufCnt;             // count of "active" bytes in buf
  261.     UCHAR   *pucBuf;             // pointer to next byte
  262.     UCHAR   aucBuf[FILEBUFSIZE]; // buffer
  263. }FILEBUFFER;
  264.  
  265.     /*---------------------------------------------------------------
  266.      * prototypes
  267.      *--------------------------------------------------------------*/
  268. int GetBufCh( FILEBUFFER* );
  269. int BufWrite( FILEBUFFER*, UCHAR*, SHORT );
  270. int BufFlush( FILEBUFFER* );
  271. FILEBUFFER *FileOpen( char*, SHORT );
  272. int FileClose( FILEBUFFER* );
  273.  
  274.  
  275. [LISTING THREE]
  276.  
  277.  
  278. /*******************************************************************
  279.  * BUFIO.C  (c) Copyright 1991, Greg Pickles, All Rights Reserved
  280.  *
  281.  * Simple buffered file I/O.
  282.  *******************************************************************/
  283. #include <stdio.h>
  284. #include <stdlib.h>
  285. #include <memory.h>
  286. #include <malloc.h>
  287. #include <fcntl.h>
  288. #include <io.h>
  289. #include <sys\types.h>
  290. #include <sys\stat.h>
  291.  
  292. #include "bufio.h"
  293.  
  294. /*******************************************************************
  295.  * GetBufCh
  296.  *  Read the next char from a file using a buffer.  Reads the file as
  297.  *  necessary.  Assumes that the file is already open.
  298.  *
  299.  *  Parameters      Description
  300.  *  ----------------------------------------------------------------
  301.  *  pstrcF          pointer to the FILEBUFFER structure for the file
  302.  *
  303.  *  Return Value
  304.  *  ------------
  305.  *  The next character from the file, if available
  306.  *  EOF if no characters are available or error
  307.  *******************************************************************/
  308. int GetBufCh( FILEBUFFER *pstrcF )
  309. {
  310.   if (pstrcF->sBufCnt == 0)
  311.     {
  312.     if ( (pstrcF->sBufCnt =
  313.          read(pstrcF->hFile,pstrcF->aucBuf,FILEBUFSIZE)) == 0 )
  314.       return EOF;
  315.     pstrcF->pucBuf=pstrcF->aucBuf;
  316.     }
  317.   pstrcF->sBufCnt--;
  318.   return (int)*(pstrcF->pucBuf++);
  319. }
  320.  
  321. /*******************************************************************
  322.  * BufWrite
  323.  *  Write a buffer of characters to an output file via a file buffer
  324.  *  structure.
  325.  *
  326.  *  Parameters      Description
  327.  *  ----------------------------------------------------------------
  328.  *  pstrcF          pointer to the FILEBUFFER structure for the file
  329.  *  pbBuf           pointer to the array of bytes to write
  330.  *  sCnt            number of bytes to write
  331.  *
  332.  *  Return Value
  333.  *  ------------
  334.  *  0 if success, non-0 if an error occurs
  335.  *******************************************************************/
  336. int BufWrite( FILEBUFFER *pstrcF, UCHAR *pbBuf, SHORT sCnt )
  337. {
  338. int iRslt;
  339.  
  340.   while (sCnt > pstrcF->sBufCnt)
  341.     {
  342.     memcpy( pstrcF->pucBuf, pbBuf, pstrcF->sBufCnt );
  343.     sCnt -= pstrcF->sBufCnt;
  344.     pbBuf += pstrcF->sBufCnt;
  345.     pstrcF->sBufCnt = 0;
  346.     if (iRslt = BufFlush(pstrcF))
  347.       return (iRslt);
  348.     }
  349.   if (sCnt > 0)
  350.     {
  351.     memcpy( pstrcF->pucBuf, pbBuf, sCnt );
  352.     pstrcF->pucBuf += sCnt;
  353.     pstrcF->sBufCnt -= sCnt;
  354.     }
  355.   return 0;
  356. }
  357.  
  358. /*******************************************************************
  359.  * BufFlush
  360.  *  Flush an output buffer to disk.
  361.  *
  362.  *  Parameters      Description
  363.  *  ----------------------------------------------------------------
  364.  *  pstrcF          pointer to the FILEBUFFER structure for the file
  365.  *
  366.  *  Return Value
  367.  *  ------------
  368.  *  0 if success, non-0 if an error occurs
  369.  *******************************************************************/
  370. int BufFlush( FILEBUFFER *pstrcF )
  371. {
  372. int iRslt;
  373.   if (pstrcF->sBufCnt != FILEBUFSIZE)
  374.     {
  375.     iRslt = write(pstrcF->hFile, pstrcF->aucBuf,
  376.                 FILEBUFSIZE-pstrcF->sBufCnt);
  377.     if (iRslt != FILEBUFSIZE-pstrcF->sBufCnt)
  378.       return errno;
  379.     pstrcF->pucBuf = pstrcF->aucBuf;
  380.     pstrcF->sBufCnt = FILEBUFSIZE;
  381.     }
  382.   return 0;
  383. }
  384.  
  385. /*******************************************************************
  386.  * FileOpen
  387.  *  Open a file for input or output using a file buffer structure.
  388.  *
  389.  *  Parameters      Description
  390.  *  ----------------------------------------------------------------
  391.  *  pszFileName     pointer to file name
  392.  *  sMode           0 for read, 1 for write
  393.  *
  394.  *  Return Value
  395.  *  ------------
  396.  *  pointer to allocated file buffer structure if success
  397.  *  NULL if error
  398.  *******************************************************************/
  399. FILEBUFFER *FileOpen( char *pszFileName, SHORT sMode )
  400. {
  401. FILEBUFFER  *pstrcFile;
  402.  
  403.                 // allocate file buffer STRCUTURE
  404.   if ( (pstrcFile=malloc(sizeof(FILEBUFFER))) == NULL )
  405.     {
  406.     printf("Error allocating file buffer FOR %s\n",pszFileName);
  407.     return NULL;
  408.     }
  409.   pstrcFile->pucBuf=pstrcFile->aucBuf;
  410.   if (sMode)
  411.     {
  412.     pstrcFile->sBufCnt=FILEBUFSIZE;
  413.     pstrcFile->hFile = open(pszFileName,
  414.                        O_BINARY|O_CREAT|O_TRUNC|O_WRONLY,S_IWRITE);
  415.     }
  416.   else
  417.     {
  418.     pstrcFile->sBufCnt=0;
  419.     pstrcFile->hFile = open(pszFileName,O_BINARY|O_RDONLY);
  420.     }
  421.   if (pstrcFile->hFile == -1)
  422.     {
  423.     printf("Error opening '%s'\n",pszFileName);
  424.     free(pstrcFile);
  425.     return NULL;
  426.     }
  427.   pstrcFile->sMode = sMode;
  428.   return pstrcFile;
  429. }
  430.  
  431. /*******************************************************************
  432.  * FileClose
  433.  *  Close a file.
  434.  *
  435.  *  Parameters      Description
  436.  *  ----------------------------------------------------------------
  437.  *  pstrcFile       pointer to FILEBUFFER for the file
  438.  *
  439.  *  Return Value
  440.  *  ------------
  441.  *  0 if success, non-0 if an error occurs
  442.  *******************************************************************/
  443. int FileClose( FILEBUFFER *pstrcFile )
  444. {
  445. int iRslt = 0;
  446.  
  447.   if (pstrcFile->sMode == 1)
  448.     BufFlush(pstrcFile);
  449.   iRslt = close(pstrcFile->hFile);
  450.   free(pstrcFile);
  451.   return iRslt;
  452. }
  453.  
  454.  
  455. [LISTING FOUR]
  456.  
  457. /*******************************************************************
  458.  * PCXHP.H  (c) Copyright 1991, Greg Pickles, All Rights Reserved
  459.  *
  460.  * Header file for FAX image print program.
  461.  *******************************************************************/
  462.     /*-------------------------------------------------------------
  463.      * structure to pass control information
  464.      *------------------------------------------------------------*/
  465. typedef struct {
  466.     SHORT sXpos;        // x pos for image on page in pixels
  467.     SHORT sYpos;        // y pos for image on page in pixels
  468.     SHORT sInv;         // TRUE to invert image
  469.     SHORT sEndAdjust;   // number of bytes at the end of a raster line
  470.                         //  to adjust because they are beyond the end
  471.                         //  of the actual image
  472.     SHORT sAdjOffset;   // offset in line of first byte to adjust
  473.     UCHAR ucMask;       // mask to OR in to the first byte that is
  474.                         //  adjusted (image may end in middle of byte)
  475. }OPTIONS;
  476.  
  477.     /*-------------------------------------------------------------
  478.      * PCX file header
  479.      *------------------------------------------------------------*/
  480. typedef struct {
  481.     UCHAR  ucPcxId;                // PCX ID, always 0x0a
  482.     UCHAR  ucVer;                  // PCX version
  483.     UCHAR  ucEncMeth;              // 1 = run length
  484.     UCHAR  ucBPP;                  // bits per pixel
  485.     USHORT usUpLeftX, usUpLeftY;   // position of upper left corner
  486.     USHORT usLoRightX, usLoRightY; // position of lower right corner
  487.     USHORT usDispXRes, usDispYRes; // resolution of display
  488.     UCHAR  aucPalette[48];         // palette data
  489.     UCHAR  ucRes;
  490.     UCHAR  ucNumPlanes;            // number of bit planes of data
  491.     USHORT usBytePerLine;          // # bytes in an raster line
  492.     UCHAR  ucRes2[60];
  493. }PCX_HDR;
  494.  
  495.     /*-------------------------------------------------------------
  496.      * Prototypes
  497.      *------------------------------------------------------------*/
  498. int PCXToHP(char*, FILEBUFFER*, OPTIONS*);
  499. void usage(void);
  500. PCX_HDR *PcxReadHeader(PCX_HDR*, FILEBUFFER*);
  501. void pcx_print_header(PCX_HDR*);
  502. UCHAR *pcx_alloc_line(PCX_HDR*, SHORT);
  503. int PcxReadLines(PCX_HDR*, UCHAR*, FILEBUFFER*, SHORT, OPTIONS*);
  504. UCHAR *pcx_test_line(PCX_HDR*, UCHAR*, SHORT, SHORT);
  505. UCHAR *ScanNE(UCHAR*, UCHAR, int);
  506. int IndexNE(UCHAR*, UCHAR, int);
  507. int CntREQ(UCHAR*, UCHAR, int);
  508. int main(int, char**);
  509.  
  510. void Scale2to3(char far*,char far*,short,short);
  511.  
  512.  
  513. [LISTING FIVE]
  514.  
  515.  
  516. /*******************************************************************
  517.  * PCXHP.C  (c) Copyright 1991, Greg Pickles, All Rights Reserved
  518.  *
  519.  * FAX to LaserJet II image print program.
  520.  *******************************************************************/
  521. #include <stdio.h>
  522. #include <stdlib.h>
  523. #include <string.h>
  524. #include <memory.h>
  525. #include <malloc.h>
  526. #include <fcntl.h>
  527. #include <io.h>
  528. #include <sys\types.h>
  529. #include <sys\stat.h>
  530. #include <conio.h>
  531.  
  532. #include "bufio.h"
  533. #include "pcxhp.h"
  534.  
  535. /*******************************************************************
  536.  * PCXToHP
  537.  *  Process a PCX file
  538.  *
  539.  *  Parameters      Description
  540.  *  ----------------------------------------------------------------
  541.  *  pszFileName     pointer to the input file name
  542.  *  pstrcOutFile    pointer to output file buffer structure
  543.  *  pstrcOpt        pointer to OPTIONS struc for processing this file
  544.  *
  545.  *  Return Value
  546.  *  ------------
  547.  *  0 if successful, non-0  if error
  548.  *******************************************************************/
  549. int PCXToHP(char *pszFileName, FILEBUFFER *pstrcOutFile,
  550.             OPTIONS *pstrcOpt)
  551. {
  552. FILEBUFFER  *pstrcInFile;
  553. PCX_HDR     strcHdr;
  554. SHORT       i, k, sXsize, sYsize, sLineBytes, sExpLineSize;
  555. UCHAR       *pucLine, *pucExpBuf;
  556. int         iCurX = -1, iCurY = -1;
  557. int         iNewX, iNewY, iFront, iBack;
  558. char        szFileName[80];
  559. char        szHpLineLead[20];
  560. char        szHpPos[50];
  561.  
  562. static  char    szPosFmtFXYO[] = "\x01b*p%dx%dY\x01b*r1A";
  563. static  char    szPosFmtY[]  = "\x01b*p%dY";
  564. static  char    szGrDataFmt[]= "\x01b*b%dW";
  565. static  char    szEndGr[]    = "\x01b*rB";
  566. static  char    szRes300[] = "\x01b*t300R";
  567.     
  568.  
  569.   strcpy(szFileName, pszFileName);       // make local copy of name
  570.   if (strchr(szFileName,'.') == NULL)    // add .PCX if needed
  571.     strcat(szFileName,".pcx");         
  572.  
  573.               // allocate input file buffer and open file
  574.   if ( (pstrcInFile=FileOpen(szFileName,0)) == NULL )
  575.     return 1;
  576.  
  577.   if (PcxReadHeader(&strcHdr,pstrcInFile) == NULL)
  578.     {
  579.     fprintf(stderr,"Error reading PCX header in file '%s'\n",
  580.             szFileName);
  581.     close(pstrcInFile->hFile);
  582.     return 3;
  583.     }
  584.  
  585.   if (strcHdr.ucNumPlanes != 1)
  586.     {
  587.     fprintf(stderr,"Error: Not a monochrome PCX file.\n");
  588.     close(pstrcInFile->hFile);
  589.     return 5;
  590.     }
  591.               // extract size of line, compute number of rows
  592.               // allocate buffer for 2 input lines
  593.   sLineBytes = strcHdr.usBytePerLine;
  594.   sYsize = strcHdr.usLoRightY - strcHdr.usUpLeftY + 1;
  595.   pucLine = malloc(2*sLineBytes);
  596.  
  597.               // determine whether any bits/bytes need to be masked
  598.               // at the end of a decompressed line
  599.   sXsize = (strcHdr.usLoRightX - strcHdr.usUpLeftX + 1);
  600.   if ( sXsize/8 < sLineBytes )
  601.     {
  602.     pstrcOpt->sEndAdjust = sLineBytes - sXsize/8;
  603.     pstrcOpt->sAdjOffset = sXsize/8;
  604.     pstrcOpt->ucMask = (UCHAR) (0xff >> sXsize%8);
  605.     }
  606.               // compute length of scaled line and allocate buffer
  607.   sExpLineSize = strcHdr.usBytePerLine + (strcHdr.usBytePerLine/2) +
  608.                 ((strcHdr.usBytePerLine & 1) ? 1 : 0);
  609.   pucExpBuf = malloc(sExpLineSize*3);
  610.  
  611.               // set HP graphics resolution to 300 DPI
  612.   BufWrite(pstrcOutFile,szRes300, strlen(szRes300));
  613.  
  614.               // init position on page    
  615.   iNewX = pstrcOpt->sXpos;
  616.   iNewY = pstrcOpt->sYpos;
  617.  
  618.   for (i=0; i<sYsize; i+=2)
  619.     {
  620.     if ( !PcxReadLines(&strcHdr, pucLine, pstrcInFile, 2, pstrcOpt) )
  621.       break;
  622.     Scale2to3(pucLine,pucExpBuf,sLineBytes,pstrcOpt->sInv);
  623.  
  624.     for (k=0; k<3; k++)
  625.       {
  626.       if ((iFront=IndexNE(pucExpBuf+k*sExpLineSize,0,sExpLineSize)) >= 0)
  627.         {
  628.         iNewX = pstrcOpt->sXpos + iFront*8;
  629.         iBack=CntREQ(pucExpBuf+(k+1)*sExpLineSize-1,0,sExpLineSize);
  630.         if (iNewX != iCurX)
  631.           {
  632.           sprintf(szHpPos,szPosFmtFXYO,iNewX,iNewY);
  633.           BufWrite(pstrcOutFile,szHpPos,strlen(szHpPos));
  634.           iCurX = iNewX;
  635.           iCurY = iNewY;
  636.           }
  637.         else if (iNewY != iCurY)
  638.           {
  639.           sprintf(szHpPos,szPosFmtY,iNewY);
  640.           BufWrite(pstrcOutFile,szHpPos,strlen(szHpPos));
  641.           iCurY = iNewY;
  642.           }
  643.                 // note: a possible optimization is to remember the
  644.                 //       previous leadin string, value of iFront,
  645.                 //       and leadin string length and only create
  646.                 //       them when they change
  647.         sprintf(szHpLineLead,szGrDataFmt, sExpLineSize-iFront-iBack);
  648.  
  649.         BufWrite(pstrcOutFile,szHpLineLead,strlen(szHpLineLead));
  650.         BufWrite(pstrcOutFile,pucExpBuf+k*sExpLineSize+iFront,
  651.                     sExpLineSize-iFront-iBack);
  652.         iCurY++;
  653.         }
  654.       iNewY++;
  655.       }
  656.  
  657.     }
  658.  
  659.   BufWrite(pstrcOutFile,szEndGr,strlen(szEndGr));
  660.   BufWrite(pstrcOutFile,"\f",1);
  661.  
  662.   free(pucLine);
  663.   free(pucExpBuf);
  664.   FileClose(pstrcInFile);
  665.   return 0;
  666. }
  667.  
  668. /*******************************************************************
  669.  * usage
  670.  *  Displays usage help and returns to system.
  671.  *
  672.  *  Parameters      Description
  673.  *  ----------------------------------------------------------------
  674.  *  none
  675.  *
  676.  *  Return Value
  677.  *  ------------
  678.  *  none
  679.  *******************************************************************/
  680. void usage(void)
  681. {
  682.   printf("PCXHP\n");
  683.   printf("  Given a .PCX file, this program creates a file which can be\n");
  684.   printf("   sent to an HP LaserJet printer to print the image.\n");
  685.   printf(" PCXHP [-xX] [-yY][-d] [-i] [-ofilename] filename\n");
  686.   printf("   Options include:               (units)              [default]\n");
  687.   printf("   -xPOS  set horizontal position (pixels from left)   [0]\n");
  688.   printf("   -yPOS  set vertical position   (pixels from bottom) [0]\n");
  689.   printf("   -d     dump PCX file info to stdout                 [off]\n");
  690.   printf("   -i     sInv image                                 [off]\n");
  691.   printf("   -oFIL  set output filename, or use SET PCXHP=filename\n");
  692.   exit(1);
  693. }
  694.  
  695. /*******************************************************************
  696.  * PcxReadHeader
  697.  *  Reads the header of a PCX file.  Assumes the file is already open
  698.  *  and its handle is in the file buffer structure.
  699.  *
  700.  *  Parameters      Description
  701.  *  ----------------------------------------------------------------
  702.  *  pstrcHdr        pointer to struct in which to store the header
  703.  *  pstrcF          pointer to file buffer struct for the file
  704.  *
  705.  *  Return Value
  706.  *  ------------
  707.  *  pointer to the header structure, if successful
  708.  *  NULL if error
  709.  *******************************************************************/
  710. PCX_HDR *PcxReadHeader(PCX_HDR *pstrcHdr, FILEBUFFER *pstrcF)
  711. {
  712.   lseek(pstrcF->hFile,0L,SEEK_SET);
  713.   if (read(pstrcF->hFile,(char*)pstrcHdr,sizeof(PCX_HDR))
  714.           != sizeof(*pstrcHdr))
  715.     return NULL;
  716.   else
  717.     return pstrcHdr;
  718. }
  719.  
  720. /*******************************************************************
  721.  * PcxReadLines
  722.  *  Reads and expands the next  N line from the PCX file.  Assumes
  723.  *  that the file pointer is positioned at the point in the file at
  724.  *  which to begin reading.  Performs data expansion as necessary.
  725.  *
  726.  *  Parameters      Description
  727.  *  ----------------------------------------------------------------
  728.  *  pstrcHdr        pointer to PCX header struct for the file
  729.  *  pbLine          pointer to the buffer in which to put lines
  730.  *  pstrcF          pointer to the opened FILEBUFFER for the file
  731.  *  sLines          number of lines to read and expand
  732.  *
  733.  *  Return Value
  734.  *  ------------
  735.  *  TRUE if success, FALSE if our of data
  736.  *******************************************************************/
  737. int PcxReadLines(PCX_HDR *pstrcHdr, UCHAR *pucLine, FILEBUFFER *pstrcF,
  738.                  SHORT sLines, OPTIONS *pstrcOpt)
  739. {
  740. int     iData, iData2;
  741. UCHAR   *pucDst, *pucLineStart;
  742. USHORT  usLSize = pstrcHdr->usBytePerLine;
  743. int     i, j;
  744.  
  745.   for (j=0, pucDst=pucLine; j<sLines; j++)
  746.     {
  747.     for (i=0, pucLineStart=pucDst; i<usLSize; )
  748.       {
  749.               // if we get EOF on the first line, return FALSE
  750.               // to indicate we're done, otherwise fill the
  751.               // rest of the lines with 0xff (i.e. blank)
  752.       if ((iData=GetBufCh(pstrcF)) == EOF)
  753.         {
  754.         if ( (j > 0) || (i > 0) )
  755.           {
  756.           memset(pucDst,0xff,usLSize-i);
  757.           i = usLSize;
  758.           pucDst += (usLSize-i);
  759.           }
  760.         else
  761.           return FALSE;
  762.         }
  763.       else
  764.         {
  765.         if ((iData & 0xc0) == 0xc0)     // check for run length
  766.           {
  767.               // read data to be repeated; if EOF, return FALSE
  768.           if ((iData2=GetBufCh(pstrcF)) == EOF)
  769.             return FALSE;
  770.           memset(pucDst, (UCHAR)iData2, iData & 0x3f);
  771.           pucDst += iData & 0x3f;
  772.           i += iData & 0x3f;
  773.           }
  774.         else
  775.           {
  776.           *pucDst++ = (UCHAR)iData;
  777.           i++;
  778.           }
  779.         }
  780.       }
  781.     if (i=pstrcOpt->sEndAdjust)
  782.       {
  783.       pucLineStart += pstrcOpt->sAdjOffset;
  784.       *pucLineStart |= pstrcOpt->ucMask;
  785.       while (--i)
  786.         *(++pucLineStart) = 0xff;
  787.       }
  788.     }
  789.   return TRUE;
  790. }
  791.  
  792. /*******************************************************************
  793.  * IndexNE
  794.  *  Scans a buffer for the first byte not equal to a specified byte.
  795.  *
  796.  *  Parameters      Description
  797.  *  ----------------------------------------------------------------
  798.  *  pbBuf           pointer to the buffer to test
  799.  *  bVal            value to test for
  800.  *  iCount          number of bytes to test
  801.  *
  802.  *
  803.  *  Return Value
  804.  *  ------------
  805.  *  -1 if the buffer contains only the specified byte
  806.  *  otherwise offset of the first byte that is not the specified byte
  807.  *******************************************************************/
  808. int IndexNE(UCHAR *bBuf, UCHAR bVal, int iCount)
  809. {
  810. int iOrig = iCount;
  811.  
  812.   while (iCount && (*bBuf == bVal))
  813.     {
  814.     iCount--;
  815.     bBuf++;
  816.     }
  817.   if (iCount)
  818.     return iOrig-iCount;
  819.   return -1;
  820. }
  821.  
  822. /*******************************************************************
  823.  * CntREQ
  824.  *  Counts the number of bytes equal to a specified byte from a
  825.  *  starting point in memory backwards.
  826.  *
  827.  *  Parameters      Description
  828.  *  ----------------------------------------------------------------
  829.  *  pbBuf           pointer to the (end of the) buffer to test
  830.  *  bVal            value to test for
  831.  *  iCount          number of bytes to test
  832.  *
  833.  *  Return Value
  834.  *  ------------
  835.  *  number of bytes found that are equal to the specified byte
  836.  *******************************************************************/
  837. int CntREQ(UCHAR *bBuf, UCHAR bVal, int iCount)
  838. {
  839. int iOrig = iCount;
  840.  
  841.   while (iCount && (*bBuf == bVal))
  842.     {
  843.     iCount--;
  844.     bBuf--;
  845.     }
  846.   return iOrig-iCount;
  847. }
  848.  
  849. /*******************************************************************
  850.  * main
  851.  *
  852.  *  Parameters      Description
  853.  *  ----------------------------------------------------------------
  854.  *  argc            argument character count
  855.  *  argp            pointer to array of pointers to args
  856.  *
  857.  *
  858.  *  Return Value
  859.  *  ------------
  860.  *  1 if error in args or opening output file
  861.  *  otherwise result of PCXToHP
  862.  *******************************************************************/
  863. int main(int argc, char *argv[])
  864. {
  865. int i;
  866. FILEBUFFER  *OutFile;
  867. char    *outfname = NULL;
  868. char    *filename = NULL;
  869.  
  870. static OPTIONS Opt = {0,0,TRUE,0,0,0};
  871.  
  872.   if (argc < 2)
  873.     usage();
  874.  
  875.   for (i=1; i<argc; i++)
  876.     {
  877.     if (argv[i][0] == '-' || argv[i][0] == '/')
  878.       switch (toupper(argv[i][1]))
  879.         {
  880.         case 'X': Opt.sXpos = atoi(argv[i]+2); break;
  881.         case 'Y': Opt.sYpos = atoi(argv[i]+2); break;
  882.         case 'I': Opt.sInv = !Opt.sInv; break;
  883.         case 'O': outfname=argv[i]+2; break;
  884.         case '?': usage(); break;
  885.         default:  fprintf(stderr, "Unknown option %s\n",argv[i]);
  886.                   usage();
  887.                   break;
  888.         }
  889.       else
  890.         filename = argv[i];
  891.     }
  892.  
  893.   if ( (outfname == NULL) && ((outfname = getenv("PCXHP")) == NULL) )
  894.     outfname = "prn";
  895.   if ( (OutFile=FileOpen(outfname,1)) == NULL )
  896.     exit(1);
  897.  
  898.   i = PCXToHP(filename, OutFile, &Opt);
  899.  
  900.   FileClose(OutFile);
  901.   return i;
  902. }
  903.  
  904.